<?php

namespace App\Models;

use App\Models\ComModel;

class LinkageModel extends ComModel
{

    protected $pids;
    protected $cache;
    protected $categorys;

    public function __construct(...$param)
    {
        parent::__construct();
        $this->tablename = 'linkage';
    }

    private function _validate($data, $id = 0)
    {
        if (!$data) {
            return ams_rt(1, '参数错误');
        }
        $data = esc($data);
        if (!$data['name']) {
            return ams_rt(1, '名称必须填写');
        }

        if (!ctype_alnum($data['code'])) {
            return ams_rt(1, '别名格式错误');
        }

        $data['type'] = isset($data['type']) ? intval($data['type']) : 0;

        $flag = $this->field_exitsts($this->tablename, 'name', $data['name'], $id);
        if ($flag) {
            return ams_rt(1, '名称已存在');
        }
        $flag = $this->field_exitsts($this->tablename, 'code', $data['code'], $id);
        if ($flag) {
            return ams_rt(1, '标识已存在');
        }
        return ams_rt(0, 'ok', $data);
    }

    // 分页
    public function limit_page($page = 0, $size = 10, $total = 0, $param = [])
    {

        $page = max(1, (int) $page);
        $total = (int) $total;

        if ($param) {
            $param = esc($param);
        }

        if ($size > 0 && !$total) {
            $select = $this->db->table($this->tablename)->select('count(*) as total');
            $param = $this->_limit_where($select, $param);
            $query = $select->get();
            if (!$query) {
                log_message('error', '数据查询失败：' . $this->tablename);
                return [[], $total, $param];
            }
            $data = $query->getRowArray();
            $total = (int) $data['total'];
            $param['total'] = $total;
            unset($select);
            if (!$total) {
                return [[], $total, $param];
            }
        }

        $select = $this->db->table($this->tablename);
        $order = 'id desc';
        $param = $this->_limit_where($select, $param);
        $size > 0 && $select->limit($size, $size * ($page - 1));
        $query = $select->orderBy($order)->get();
        if (!$query) {
            log_message('error', '数据查询失败：' . $this->tablename);
            return [[], $total, $param];
        }
        $data = $query->getResultArray();
        $param['order'] = $order;
        $param['total'] = $total;

        return [$data, $total, $param];

    }

    /**
     * 条件查询
     *
     * @param    object    $select    查询对象
     * @param    intval    $where    是否搜索
     * @return    intval
     */
    protected function _limit_where(&$select, $param)
    {
        // 条件搜索
        if ($param) {
            if (isset($param['id']) && $param['id']) {
                $select->where('id', (int) $$param['id']);
            }
            if (isset($param['name']) && $param['name']) {
                $select->like('name', urldecode($param['name']));
            }
            if (isset($param['code']) && $param['code']) {
                $select->where('code', $param['code']);
            }
        }
        return $param;
    }

    public function add($data)
    {
        $rt = $this->_validate($data);
        if ($rt['code']) {
            return $rt;
        }
        $data = $rt['data'];
        $this->db->table($this->tablename)->insert([
            'name' => $data['name'],
            'code' => $data['code'],
            'type' => $data['type'],
        ]);
        $id = $this->db->insertID();
        if ($id) {
            $rt = $this->create($id);
            return ams_rt(0, '操作成功', $id);
        }
        return ams_rt(1, '操作失败', $data);
    }

    public function get($id)
    {
        $id = intval($id);
        $data = $this->db->table($this->tablename)->where('id', $id)->get()->getRowArray();
        return $data;
    }

    public function edit($id, $data)
    {
        $id = intval($id);
        $rt = $this->_validate($data, $id);
        if ($rt['code']) {
            return $rt;
        }
        $data = $rt['data'];
        $this->db->table($this->tablename)->where('id', $id)->update([
            'name' => $data['name'],
            'code' => $data['code'],
            'type' => $data['type'],
        ]);

        return ams_rt(0, '操作成功', $id);
    }

    public function del($id)
    {
        $id = intval($id);
        $row = $this->db->table($this->tablename)->where('id', $id)->get()->getRowArray();
        if (!$row) {
            return ams_rt(1, '数据不存在', $id);
        }
        $this->db->table($this->tablename)->where('id', $id)->delete();
        $table = $this->db->prefixTable('linkage_' . $id);
        $this->db->query('DROP TABLE IF EXISTS `' . $table . '`');
        return ams_rt(0, '操作成功', $id);
    }

    // 创建联动数据表
    public function create($id)
    {
        $data = $this->get($id);
        // 创建数据表
        $table = $this->db->prefixTable('linkage_' . $id);
        $this->db->query('DROP TABLE IF EXISTS `' . $table . '`');
        $this->db->query(trim("CREATE TABLE IF NOT EXISTS `{$table}` (
		  `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
		  `pid` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT '上级id',
		  `pids` varchar(255) NOT NULL DEFAULT '' COMMENT '所有上级id',
		  `name` varchar(255) NOT NULL DEFAULT '' COMMENT '菜单名称',
		  `cname` varchar(255) NOT NULL DEFAULT '' COMMENT '菜单别名',
		  `child` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否有下级',
		  `status` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '前端隐藏',
		  `childids` varchar(255) NOT NULL DEFAULT '' COMMENT '下级所有id',
		  `displayorder` int(10) unsigned NOT NULL DEFAULT '0',
		  PRIMARY KEY (`id`),
		  KEY `cname` (`cname`),
		  KEY `status` (`status`),
		  KEY `list` (`displayorder`)
        ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='联动菜单" . $data['name'] . "数据表'"));

        if ($this->db->tableExists('linkage_' . $id)) {
            return ams_rt(0, '操作成功');
        }
        $this->del($id);
        return ams_rt(1, '操作失败');
    }

    // 批量删除
    public function delete_all($ids)
    {
        foreach ($ids as $id) {
            $id = intval($id);
            $row = $this->db->table($this->tablename)->where('id', $id)->get()->getRowArray();
            if (!$row) {
                return ams_rt(1, '数据不存在', $id);
            }
            $this->db->table($this->tablename)->where('id', $id)->delete();
            // 删除表数据
            $table = $this->db->tableExists('linkage_' . $id);
            $this->db->query('DROP TABLE IF EXISTS `' . $table . '`');
        }

        return ams_rt(0, '操作成功');
    }

    // 批量删除
    public function delete_list_all($key, $ids)
    {
        foreach ($ids as $id) {
            $row = $this->db->table('linkage_' . $key)->get(intval($id));
            if (!$row) {
                return ams_rt(1, '数据不存在', $id);
            }
            if ($row['child']) {
                $rt = $this->db->table('linkage_' . $key)->deleteAll(explode(',', $row['childids']));
            }
            $rt = $this->db->table('linkage_' . $key)->delete($id);
            if (!$rt['code']) {
                return ams_rt(0, $rt['msg']);
            }
        }
        return ams_rt(1, '');
    }

    // 批量移动分类
    public function edit_pid_all($key, $pid, $ids)
    {
        foreach ($ids as $id) {
            $row = $this->db->table('linkage_' . $key)->get(intval($id));
            if (!$row) {
                return ams_rt(1, '数据不存在', $id);
            }

            $rt = $this->db->table('linkage_' . $key)->update($id, ['pid' => $pid]);
            if (!$rt['code']) {
                return ams_rt(0, $rt['msg']);
            }
        }
        $this->repairList(['id' => $key, 'type' => 0]);
        return ams_rt(0, '操作成功');
    }

    // 分页
    public function limit_page_list($page = 0, $size = 10, $total = 0, $param = [])
    {
        $page = max(1, (int) $page);
        $total = (int) $total;

        if ($param) {
            $param = esc($param);
        }

        if ($size > 0 && !$total) {
            $select = $this->db->table($this->tablename . '_' . $param['catid'])->select('count(*) as total');
            $param = $this->_limit_where_list($select, $param);
            $query = $select->get();
            if (!$query) {
                log_message('error', '数据查询失败：' . $this->tablename . '_' . $param['catid']);
                return [[], $total, $param];
            }
            $data = $query->getRowArray();
            $total = (int) $data['total'];
            $param['total'] = $total;
            unset($select);
            if (!$total) {
                return [[], $total, $param];
            }
        }

        $select = $this->db->table($this->tablename . '_' . $param['catid']);
        $order = 'id desc';
        $param = $this->_limit_where_list($select, $param);
        $size > 0 && $select->limit($size, $size * ($page - 1));
        $query = $select->orderBy($order)->get();
        if (!$query) {
            log_message('error', '数据查询失败：' . $this->tablename . '_' . $param['catid']);
            return [[], $total, $param];
        }
        $data = $query->getResultArray();
        $param['order'] = $order;
        $param['total'] = $total;

        return [$data, $total, $param];

    }

    /**
     * 条件查询
     *
     * @param    object    $select    查询对象
     * @param    intval    $where    是否搜索
     * @return    intval
     */
    protected function _limit_where_list(&$select, $param)
    {
        // 条件搜索
        if ($param) {
            if (isset($param['pid']) && is_numeric($param['pid'])) {
                $select->where('pid', (int) $param['pid']);
            }
            if (isset($param['id']) && $param['id']) {
                $select->where('id', (int) $$param['id']);
            }
            if (isset($param['name']) && $param['name']) {
                $select->like('name', urldecode($param['name']));
            }
            if (isset($param['code']) && $param['code']) {
                $select->where('code', $param['code']);
            }
        }
        return $param;
    }

    // 添加子内容
    public function addList($key, $data)
    {
        $data = esc($data);
        $pid = intval($data['pid']);
        $py = new \App\Libraries\Pinyin();

        if (isset($data['all']) && $data['all']) {
            $c = 0;
            $names = explode(PHP_EOL, trim($data['all']));
            foreach ($names as $t) {
                $t = trim($t);
                if (!$t) {
                    continue;
                }
                $cname = $py->result($t);
                $cf = $this->db->table('linkage_' . $key)->where('cname', $cname)->countAllResults();
                $this->db->table('linkage_' . $key)->insert(array(
                    'pid' => $pid,
                    'pids' => '',
                    'name' => $t,
                    'child' => 0,
                    'cname' => $cname,
                    'status' => 0,
                    'childids' => '',
                    'displayorder' => 0,
                ));
                $id = $this->db->insertID();
                if (!$id) {
                    return ams_rt(1, '操作失败');
                }
                if ($cf) {
                    $this->db->table('linkage_' . $key)->where('id', $id)->update(['cname' => $cname . $id]);
                }
                $c++;
            }
            // 更新pid
            $pid && $this->db->table('linkage_' . $key)->update($pid, ['child' => 1]);
            $this->repairList(['id' => $key, 'type' => 0]);
            return ams_rt(0, '批量添加' . $c . '个');
        } else {
            // 单个
            $data['name'] = trim($data['name']);
            if (!$data['name']) {
                return ams_rt(1, '名称不能为空');
            } elseif (!$data['cname']) {
                return ams_rt(1, '别名不能为空');
            } elseif ($this->db->table('linkage_' . $key)->where('cname', $data['cname'])->countAllResults()) {
                return ams_rt(1, '别名已经存在');
            }
            $this->db->table('linkage_' . $key)->insert([
                'pid' => $pid,
                'pids' => '',
                'name' => $data['name'],
                'child' => 0,
                'cname' => $data['cname'],
                'status' => 0,
                'childids' => '',
                'displayorder' => 0,
            ]);
            $id = $this->db->insertID();
            if (!$id) {
                return ams_rt(1, '操作失败');
            }
            $pid && $this->db->table('linkage_' . $key)->where('id', $pid)->update(['child' => 1]);
            $this->repairList(['id' => $key, 'type' => 0]);
            return ams_rt(0, '操作成功');
        }
        return ams_rt(1, '未知错误');
    }

    public function editList($key, $id, $data)
    {
        $data = esc($data);
        $key = intval($key);
        $id = intval($id);
        $pid = intval($data['pid']);

        $data['name'] = trim($data['name']);
        if (!$data['name']) {
            return ams_rt(1, '名称不能为空');
        } elseif (!$data['cname']) {
            return ams_rt(1, '别名不能为空');
        } elseif ($this->db->table('linkage_' . $key)->where('id<>' . $id)->where('cname', $data['cname'])->countAllResults()) {
            return ams_rt(1, '别名已经存在');
        }
        $this->db->table('linkage_' . $key)->where('id', $id)->update($data);
        $this->repairList(['id' => $key, 'type' => 0]);
        return ams_rt(0, '操作成功');
    }

    public function getListById($key, $id)
    {
        $id = intval($id);
        $key = intval($key);
        if (!$id || !$key) {
            return [];
        }
        $data = $this->db->table($this->tablename . '_' . $key)->where('id', $id)->get()->getRowArray();
        return $data;
    }

    /**
     * 全部子菜单数据
     *
     * @param    array    $link
     * @param    intval    $pid
     * @return    array
     */
    public function getList($link, $pid = 'NULL')
    {

        $key = (int) $link['id'];

        if ($pid === 'NULL') {
            $name = 'linkage-cahce-list-' . $key . '-' . $pid;
            $data = \Phpcmf\Service::L('cache')->get_data($name);
            if ($data) {
                return $data;
            }
            $db = $this->db->table('linkage_' . $key);
            // 站点查询
            $link['type'] == 1 && $db->where('site', SITE_ID);
            // 获取菜单数据
            $menu = $db->orderBy('displayorder ASC,id ASC')->get()->getResultArray();
            if (!$menu) {
                return [];
            }
            // 格式返回数据
            $data = [];
            foreach ($menu as $t) {
                $data[$t['id']] = $t;
            }
            \Phpcmf\Service::L('cache')->set_data($name, $data);
        } else {
            $db = $this->db->table('linkage_' . $key);
            // 站点查询
            $link['type'] == 1 && $db->where('site', SITE_ID);
            $menu = $db->where('pid', (int) $pid)->orderBy('displayorder ASC,id ASC')->get()->getResultArray();
            if (!$menu) {
                return [];
            }
            // 格式返回数据
            $data = [];
            foreach ($menu as $t) {
                $data[$t['id']] = $t;
            }
        }

        return $data;
    }

    public function switchListStatus($key, $id, $value)
    {
        if (!$id || !$key) {
            return ams_rt(1, '参数错误');
        }
        $key = intval($key);
        $id = intval($id);
        $row = $this->db->table($this->tablename . '_' . $key)->select('id,name,status')->where('id', $id)->get()->getRowArray();
        if (!$row) {
            return ams_rt(1, '数据不存在');
        }
        $this->db->table($this->tablename . '_' . $key)->where('id', $id)->update(['status' => intval($value)]);
        return ams_rt(0, '操作成功', $row);
    }

    public function getListSelects($key, $pid = 0)
    {
        if (!$key) {
            return [];
        }
        $key = intval($key);
        $data = $this->db->table($this->tablename . '_' . $key)->get()->getResultArray();
        if (!$data) {
            return [];
        }
        $tree = new \App\Libraries\Tree();
        $data = $tree->get($data);
        return $data;
    }

    /**
     * 获取父栏目ID列表
     *
     * @param    integer    $catid    栏目ID
     * @param    array    $pids    父目录ID
     * @param    integer    $n        查找的层次
     * @return    string
     */
    private function get_pids($catid, $pids = '', $n = 1)
    {

        if ($n > 100 || !$this->categorys || !isset($this->categorys[$catid])) {
            return false;
        }

        $pid = $this->categorys[$catid]['pid'];
        $pids = $pids ? $pid . ',' . $pids : $pid;
        $pid && $pids = $this->get_pids($pid, $pids, ++$n);

        return $pids;
    }

    /**
     * 获取子栏目ID列表
     *
     * @param    $catid    栏目ID
     * @return    string
     */
    private function get_childids($catid, $n = 1)
    {

        $childids = $catid;

        if ($n > 100 || !is_array($this->categorys)
            || !isset($this->categorys[$catid])) {
            return $childids;
        }

        if (isset($this->pids[$catid]) && $this->pids[$catid]) {
            foreach ($this->pids[$catid] as $id) {
                $cat = $this->categorys[$id];
                // 避免造成死循环
                $cat['pid']
                && $id != $catid
                && $cat['pid'] == $catid
                && $this->categorys[$catid]['pid'] != $id
                && $childids .= ',' . $this->get_childids($id, ++$n);
            }
        }

        return $childids;
    }

    /**
     * 修复菜单数据
     */
    public function repairList($link)
    {
        if (!$link) {
            return;
        }

        $this->categorys = $categorys = [];

        $table = 'linkage_' . $link['id'];
        $_data = $this->db->table($table)->orderBy('displayorder ASC,id ASC')->get()->getResultArray();
        if (!$_data) {
            return;
        }

        // 全部栏目数据
        foreach ($_data as $t) {
            $this->pids[$t['pid']][] = $t['id']; // 归类
            $categorys[$t['id']] = $this->categorys[$t['id']] = $t;
        }

        foreach ($this->categorys as $catid => $cat) {
            $this->categorys[$catid]['pids'] = $this->get_pids($catid);
            $this->categorys[$catid]['childids'] = $this->get_childids($catid);
            $this->categorys[$catid]['child'] = is_numeric($this->categorys[$catid]['childids']) ? 0 : 1;
            // 当库中与实际不符合才更新数据表
            ($categorys[$catid]['pids'] != $this->categorys[$catid]['pids']
                || $categorys[$catid]['childids'] != $this->categorys[$catid]['childids']
                || $categorys[$catid]['child'] != $this->categorys[$catid]['child'])
            && $this->db->table($table)->where('id', $cat['id'])->update([
                'pids' => $this->categorys[$catid]['pids'],
                'child' => $this->categorys[$catid]['child'],
                'childids' => $this->categorys[$catid]['childids'],
            ]);
        }

        return $this->categorys;
    }

    // 缓存
    public function cache()
    {
        // 生成新缓存
        $linkage = $this->db->table('linkage')->get()->getResultArray();
        if ($linkage) {
            foreach ($linkage as $link) {
                $cid = $data = $lv = [];
                $list = $this->repairList($link);
                if ($list) {
                    foreach ($list as $t) {
                        if ($t['status']) {
                            continue;
                        }
                        $lv[] = substr_count($t['pids'], ',');
                        $t['ii'] = $t['id'];
                        $t['id'] = $t['cname'];
                        $cid[$t['ii']] = $t['id'];
                        $data[$t['cname']] = $t;
                    }
                }
                $this->cache->save('linkage-' . $link['code'], $data, YEAR);
                $this->cache->save('linkage-' . $link['code'] . '-id', $cid, YEAR);
                $this->cache->save('linkage-' . $link['code'] . '-key', $link['id'], YEAR);
                $this->cache->save('linkage-' . $link['code'] . '-level', $lv ? max($lv) : 0, YEAR);
            }
        }

        return;
    }

}
